package com.liuya.db.script;

import bsh.EvalError;
import bsh.Interpreter;

import com.liuya.entitle.BusinessDataTestResult;
import com.liuya.safe.util.Constants;
import com.liuya.safe.model.SafeUser;
import com.liuya.safe.policy.service.QueryManagerService;

import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.Map;

public class BusinessData extends AbstractPolicy implements Script, Serializable {
    public String getRule() {
        StringBuffer buff = new StringBuffer();
        if (isRawScript()) {
            buff.append(getRawScript().toScript()).append("\n");
        } else {
            buff.append("return ").append(getExprGroup().toScript()).append(";\n");
        }
        return buff.toString();
    }

    public String toScript() {
        if (getScript() == null) {

            StringBuffer buff = new StringBuffer();
            buff.append("java.util.Map " + Constants.VARIABLE_MAP + " = new java.util.HashMap();\n");
            int count = getDefineVaribles().size();
            for (int i = 0; i < count; i++) {
                DefineVariable defineVariable = (DefineVariable) getDefineVaribles().get(i);
                if (defineVariable instanceof QueryRef) {
                    QueryRef queryRef = (QueryRef) defineVariable;
                    if (getExprGroup().isUsedByInExprOrNotInExpr(queryRef.getVariableName())) {
                        buff.append(queryRef.toScript(true));
                    } else {
                        buff.append(queryRef.toScript(false));
                    }
                } else {
                    buff.append(defineVariable.toScript());
                }
                buff.append(Constants.VARIABLE_MAP + ".put( \"" + defineVariable.getVariableName() + "\", " + defineVariable.getVariableName() + ");\n");
            }
            buff.append("\n");
            // return values is "isBusinessDataValid"
            String isBusinessDataValid = Constants.IS_BUSINESS_DATA_VALID;
            if (isRawScript()) {
                buff.append(getRawScript().toScript() + ";\n");
                int index = buff.indexOf("return");
                if (index >= 0) {
                    buff.replace(index, index + 6, " boolean " + isBusinessDataValid + " = ");
                    buff.append(";\n");
                } /*
				 * else { buff.append(" boolean " + isBusinessDataValid +
				 * " = false;"); }
				 */
            } else {
                buff.append(" boolean ").append(isBusinessDataValid).append(" = ( ").append(getExprGroup().toScript()).append(" ); \n");
            }

            setScript(buff.toString());
            // this.script = buff.toString();
        }
        return getScript();
    }

    public BusinessDataTestResult test(SafeUser user, Map context, QueryManagerService queryManager) {
        BusinessDataTestResult result = new BusinessDataTestResult();
        Interpreter interpreter = new Interpreter();
        String script = toScript();
        try {
            eval(interpreter, user, context, queryManager);
            Boolean contain = (Boolean) interpreter.get(Constants.IS_BUSINESS_DATA_VALID);
            Map variableMap = (Map) interpreter.get(Constants.VARIABLE_MAP);
            result.setValid(contain.booleanValue());
            result.setFailed(false);
            result.setScript(script);
            result.setVariableMap(variableMap);
        } catch (EvalError e) {
            result.setFailed(true);
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            result.setErrorMessage(sw.toString());
            result.setScript(script);
        }
        return result;
    }

    private void eval(Interpreter interpreter, SafeUser user, Map context, QueryManagerService queryManager) throws EvalError {
        String script = toScript();
        // Set variables
        interpreter.set(Constants.USER_KEY, user);
        interpreter.set(Constants.CONTEXT, context);
        interpreter.set(Constants.QUERY_MANAGER, queryManager);

        java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm");
        interpreter.set(Constants.SIMPLE_DATE_FORMAT, format);
        // eval the rule
        interpreter.eval(script);
    }
}
